﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Threading;
using Sebarf.Services.Interfaces;

#endregion

namespace Sebarf.Services.Impl {
	/// <summary>
	/// This class collects monitoring data of all services and provides them to the caller. Using
	/// this service is easier then collecting the data manually.
	/// </summary>
	public class DiagnosticsDataCollectorService : Service, IDiagnosticsDataCollectorService {
		#region Public Properties

		[ServiceRequest]
		public IDiagnosticsServiceLocatorService DiagnosticsServiceLocatorService { get; set; }

		/// <summary>
		/// Configuration parameter specifying the collection interval
		/// </summary>
		public int CollectionIntervalMilliseconds { get; set; }

		/// <summary>
		/// Configuratin parameter specifying how many history entries to keep
		/// </summary>
		public int CountMaxCollectedEntries { get; set; }

		#endregion

		#region Public Methods

		/// <summary>
		/// Constructor, defines default configuration values.
		/// </summary>
		public DiagnosticsDataCollectorService() {
			CollectionIntervalMilliseconds = 2000;
			CountMaxCollectedEntries = 100;
		}

		#endregion

		/// <summary>
		/// A container holding the data. The Dictionary's key is a string composed of the name of a service and and the name of the data service of the services.
		/// The list contains the effectively monitored data.
		/// </summary>
		private readonly Dictionary<string, List<ExtendedServiceStatisticEntry>> m_data =
			new Dictionary<string, List<ExtendedServiceStatisticEntry>>();

		/// <summary>
		/// The timer
		/// </summary>
		private DispatcherTimer m_worker = new DispatcherTimer();

		#region IDiagnosticsDataCollectorService Members

		/// <summary>
		/// returns the collected data. The key of the KeyValuePair contains a string composed out of the
		/// name of the service + name of the serie.
		/// </summary>
		/// <returns></returns>
		public KeyValuePair<string, List<ExtendedServiceStatisticEntry>>[] GetCollectedDiagnosticsDataOverTime() {
			return m_data.ToArray();
		}

		#endregion

		/// <summary>
		/// The service setup method, starts a timer which collects the data
		/// </summary>
		public override void DoSetup() {
			base.DoSetup();
			m_worker = new DispatcherTimer(DispatcherPriority.Background);
			m_worker.Interval = new TimeSpan(0, 0, 0, 0, CollectionIntervalMilliseconds);
			m_worker.Tick += OnWorkerTick;
			m_worker.Start();
		}

		/// <summary>
		/// The shut down method, stops the collection timer
		/// </summary>
		public override void DoShutdown() {
			base.DoShutdown();
			m_worker.Tick -= OnWorkerTick;
			m_worker.Stop();
		}

		/// <summary>
		/// Method called by the timer, collects the monitoring data of each service
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnWorkerTick(object sender, EventArgs e) {
			foreach (
				IMonitorableService service in DiagnosticsServiceLocatorService.GetAllRegisteredServices<IMonitorableService>()) {
				ServiceStatistics statistics = service.CollectAndGetServiceStatistics();
				foreach (ServiceStatisticEntry entry in statistics.ServiceStatisticEntries) {
					string key = statistics.ServiceName + "." + entry.Key;
					if (!m_data.ContainsKey(key)) {
						m_data.Add(key, new List<ExtendedServiceStatisticEntry>());
					}
					m_data[key].Add(new ExtendedServiceStatisticEntry { ServiceStatisticEntry = entry, ServiceStatistics = statistics });
					if (m_data[key].Count > CountMaxCollectedEntries) {
						m_data[key].RemoveAt(0);
					}
				}
			}
		}
	}
}